﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;

namespace Mesuro.GUI {
	/// <summary>
	/// Interaction logic for ResizeHost.xaml
	/// </summary>
	[TemplateVisualState( GroupName = "SelectionStates", Name = "Selected" )]
	[TemplateVisualState( GroupName = "SelectionStates", Name = "Unselected" )]
	[TemplatePart( Name = "PART_Top", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_Left", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_Bottom", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_Right", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_TopLeft", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_TopRight", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_BottomLeft", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_BottomRight", Type = typeof( Thumb ) )]
	[TemplatePart( Name = "PART_Move", Type = typeof( Thumb ) )]
	public partial class ResizeHost : ContentControl {
		public static readonly string[] RESIZE_HANDLE_NAMES = { "PART_Top", "PART_Left", "PART_Bottom", "PART_Right", "PART_TopLeft", "PART_TopRight", "PART_BottomLeft", "PART_BottomRight" };

		#region DP: Left
		public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached( "Left", typeof( double ), typeof( ResizeHost ), new FrameworkPropertyMetadata( 10d, FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.Inherits, LeftChangedStatic, LeftCoerceStatic ) );
		public double Left {
			get { return (double)GetValue( LeftProperty ); }
			set { SetValue( LeftProperty, value ); }
		}
		public static double GetLeft( DependencyObject element ) { return (double)element.GetValue( LeftProperty ); }
		public static void SetLeft( DependencyObject element, double value ) { element.SetValue( LeftProperty, value ); }
		private static void LeftChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		private static object LeftCoerceStatic( DependencyObject sender, object baseValue ) {
			return Math.Max( 0, (double)baseValue );
		}
		#endregion

		#region DP: Top
		public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached( "Top", typeof( double ), typeof( ResizeHost ), new FrameworkPropertyMetadata( 10d, FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.Inherits, TopChangedStatic, TopCoerceStatic ) );
		public double Top {
			get { return (double)GetValue( TopProperty ); }
			set { SetValue( TopProperty, value ); }
		}
		public static double GetTop( DependencyObject element ) { return (double)element.GetValue( TopProperty ); }
		public static void SetTop( DependencyObject element, double value ) { element.SetValue( TopProperty, value ); }
		private static void TopChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		private static object TopCoerceStatic( DependencyObject sender, object baseValue ) {
			return Math.Max( 0, (double)baseValue );
		}
		#endregion

		#region DP: ZIndex
		public static readonly DependencyProperty ZIndexProperty = Canvas.ZIndexProperty.AddOwner( typeof( ResizeHost ), new FrameworkPropertyMetadata( 0, FrameworkPropertyMetadataOptions.None, ZIndexChangedStatic, ZIndexCoerceStatic ) );
		public int ZIndex {
			get { return (int)GetValue( ZIndexProperty ); }
			set { SetValue( ZIndexProperty, value ); }
		}
		public static int GetZIndex( DependencyObject element ) { return (int)element.GetValue( ZIndexProperty ); }
		public static void SetZIndex( DependencyObject element, int value ) { element.SetValue( ZIndexProperty, value ); }
		private static void ZIndexChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		private static object ZIndexCoerceStatic( DependencyObject sender, object baseValue ) {
			/*if (GetIsSelected( sender ))
				return int.MaxValue;
			else*/
			return baseValue;
		}
		#endregion

		#region DP: IsSelected
		public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner( typeof( ResizeHost ), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.None, IsSelectedChangedStatic ) );
		public bool IsSelected {
			get { return (bool)GetValue( IsSelectedProperty ); }
			set { SetValue( IsSelectedProperty, value ); }
		}
		public static bool GetIsSelected( DependencyObject element ) { return (bool)element.GetValue( IsSelectedProperty ); }
		public static void SetIsSelected( DependencyObject element, bool value ) { element.SetValue( IsSelectedProperty, value ); }
		private static void IsSelectedChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
			sender.CoerceValue( ZIndexProperty );
		}
		#endregion

		#region DP: HandleOpacity
		public static readonly DependencyProperty HandleOpacityProperty = DependencyProperty.RegisterAttached( "HandleOpacity", typeof( double ), typeof( ResizeHost ), new FrameworkPropertyMetadata( 1d, FrameworkPropertyMetadataOptions.None, HandleOpacityChangedStatic ) );
		public double HandleOpacity {
			get { return (double)GetValue( HandleOpacityProperty ); }
			set { SetValue( HandleOpacityProperty, value ); }
		}
		public static double GetHandleOpacity( DependencyObject element ) { return (double)element.GetValue( HandleOpacityProperty ); }
		public static void SetHandleOpacity( DependencyObject element, double value ) { element.SetValue( HandleOpacityProperty, value ); }
		private static void HandleOpacityChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		static ResizeHost() {
			FocusableProperty.OverrideMetadata( typeof( ResizeHost ), new FrameworkPropertyMetadata( false ) );
			WidthProperty.OverrideMetadata( typeof( ResizeHost ), new FrameworkPropertyMetadata( 250d ) );
			HeightProperty.OverrideMetadata( typeof( ResizeHost ), new FrameworkPropertyMetadata( 250d ) );
		}
		public ResizeHost() {
			InitializeComponent();
		}

		public override void OnApplyTemplate() {
			base.OnApplyTemplate();

			Thumb th;
			foreach (String name in RESIZE_HANDLE_NAMES) {
				th = GetTemplateChild( name ) as Thumb;
				if (th != null)
					th.DragDelta += dragResize;
			}

			th = GetTemplateChild( "PART_Move" ) as Thumb;
			if (th != null)
				th.DragDelta += dragMove;

		}

		private void dragMove( object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e ) {
			Left += e.HorizontalChange;
			Top += e.VerticalChange;
		}

		private void dragResize( object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e ) {
			double oldLeft = Left;
			double oldTop = Top;

			switch (((Thumb)sender).HorizontalAlignment) {
				case HorizontalAlignment.Right:
					Width = Math.Max( 0, ActualWidth + e.HorizontalChange );
					break;
				case HorizontalAlignment.Left:
					Width = Math.Max( 0, ActualWidth - e.HorizontalChange );
					Left = oldLeft + e.HorizontalChange;
					break;
			}
			switch (((Thumb)sender).VerticalAlignment) {
				case VerticalAlignment.Bottom:
					Height = Math.Max( 0, ActualHeight + e.VerticalChange );
					break;
				case VerticalAlignment.Top:
					Height = Math.Max( 0, ActualHeight - e.VerticalChange );
					Top = oldTop + e.VerticalChange;
					break;
			}
		}
	}
}
